/*
 * @Author: 肖思汗
 * @Date: 2020-03-20 16:43:46
 * @Last Modified by: 肖思汗
 * @Last Modified time: 2020-08-16 22:54:27
 */
// react tsx 组件例子
import React from "react";
import styles from "./MyInput.less";
import ReactMixinComponent from "@ReactMixinComponent";

enum Composition {
    END = "end", //  中文输入完成
    START = "start", // 中文输入开始
}

export interface MyInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
}

export default class MyInput<P> extends ReactMixinComponent<MyInputProps & P, any> {

    constructor(props: Readonly<MyInputProps & P>) {
        super(props);
    }

    // 输入框的输入状态
    CompositionState: Composition = Composition.END;

    input!: HTMLInputElement;

    propsHasValue(props = this.props) {
        return props.hasOwnProperty("value");
    }

    componentDidMount() {

        // 设置并过滤初始值
        const { value } = this.props;
        if (this.propsHasValue()) {
            this.input.value = this.verify(String(value));
        }

    }

    // 提取有效字符
    verify = (text: string) => {

        let validText = text.match(/([^\x00-\xff]|\d)+/g) || [];

        return validText.join("");
    }

    isPaste: boolean = false;

    onInput = (e: React.ChangeEvent<HTMLInputElement>) => {

        if (this.CompositionState === Composition.END) {

            const { onChange } = this.props;

            // 如果输入了有效字符 就执行 onChange 回调
            if (this.setValue(e.target.value) || this.isPaste === true) {
                onChange && onChange(e);
                this.isPaste = false;
            }

        }

    }

    //复制操作一定会触发onChange 回调
    onPaste = (e: any) => {
        this.isPaste = true;
    }

    // 给input 设置值的同时保留 input的光标位置
    setValue = (value: string) => {

        let selectionStart = Number(this.input.selectionStart);

        let validVal = this.verify(value);

        //  输入了有效字符就不赋值
        if (this.input.value === validVal) {

            return true;// 赋值成功    

            // 输入了无效值后 过滤后的值与input里面是相同的, 光标就要往前进一位
        } else {

            // 去除无效字符后, 光标要向前移动的距离
            let moveLength = this.input.value.length - validVal.length;

            this.input.value = validVal;

            requestAnimationFrame(() => {
                this.input.value = validVal;
            });

            // 如果输入了多个无效字符 光标就要向前移动字符的数量
            this.input.selectionStart =
                this.input.selectionEnd =
                Math.max(0, selectionStart - moveLength);

            return false; // 赋值失败赋值

        }

    }

    componentWillReceiveProps(preProps: { hasOwnProperty?: any; value?: any; }) {

        // 如果父组件有传值给子组件就用父组件的值复制给input
        if (preProps.hasOwnProperty("value")) {
            const { value } = preProps;
            this.setValue(value);
        }
    }

    onCompositionStart = (e: any) => {
        // 记录中文输入状态
        this.CompositionState = Composition.START;
    }

    onCompositionEnd = (e: any) => {
        // 记录中文输入状态
        this.CompositionState = Composition.END;

        this.onInput(e);
    }

    render() {

        const { onInput, onChange, className, value, defaultValue, ...other } = this.props;

        return (
            <input
                className={`${className} ${styles.MyInput}`}
                ref={dom => {
                    if (dom) {
                        this.input = dom;
                        this.input.value = this.verify(String(value || defaultValue || ""))
                    }
                }}
                onInput={this.onInput}
                onPaste={this.onPaste}
                defaultValue={this.verify(String(defaultValue))}
                onCompositionStart={this.onCompositionStart}
                onCompositionEnd={this.onCompositionEnd}
                {...other}
            />
        )
    }
}
